/*
 * Copyright 2011-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0.
 * See `LICENSE` in the project root for license information.
 */

package me.ijleex.mgmt.framework.concurrent;

import java.util.concurrent.TimeUnit;

/**
 * Object wait、notify、notifyAll 方法使用示例
 *
 * <p>wait()、notify/notifyAll() 方法的执行依赖于 Object 对象的 `monitor`，所以这几个方法必须在 Object 类；</p>
 * <p>必须在 `synchronized` 同步代码块中使用 wait()、notify/notifyAll() 方法，否则会报 {@link IllegalMonitorStateException} 异常；
 * 因为不在 `synchronized` 块中使用这三个方法，可能会出现 {@code 竞态条件（race condition）}。</p>
 *
 * <p><b>在安全领域，当一个原本应该是原子操作的操作分成两步（或多步）时，我们就说这里出现了竞态条件。</b></p>
 *
 * <p>javap -c -l WaitNotifyDemo.class</p>
 *
 * @author liym
 * @see Object#wait()
 * @see Object#notify()
 * @see Object#notifyAll()
 * @since 2020-06-11 22:45 新建
 */
final class WaitNotifyDemo {

    private final Object monitor = new Object();

    private WaitNotifyDemo() {}

    void waitNotify() {
        new Thread(() -> {
            System.out.println("等待阻塞 1");
            synchronized (this.monitor) {
                try {
                    System.out.println("开始阻塞 1");
                    TimeUnit.SECONDS.sleep(1L);
                    System.out.println("开始阻塞 wait 1");
                    this.monitor.wait();
                    System.out.println("阻塞结束 1");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(() -> {
            System.out.println("等待阻塞 2");
            synchronized (this.monitor) {
                System.out.println("开始阻塞 2");
                try {
                    TimeUnit.SECONDS.sleep(5L);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
                this.monitor.notifyAll();
                System.out.println("开始阻塞 notify 2");
            }
        }).start();
    }

    public static void main(String[] args) {
        WaitNotifyDemo demo = new WaitNotifyDemo();
        demo.waitNotify();
    }

}
